package edu.nwpu.zya.coreops.modules.job.task.rds;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import edu.nwpu.zya.coreops.common.utils.Constant;
import edu.nwpu.zya.coreops.common.utils.RandomUtils;
import edu.nwpu.zya.coreops.config.ElasticSearchConfig;
import edu.nwpu.zya.coreops.modules.job.task.ITask;
import edu.nwpu.zya.coreops.modules.monitor.entity.MetricEntity;
import edu.nwpu.zya.coreops.modules.monitor.service.MetricService;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 模拟RDS定时任务
 * 周期为1分钟
 * Cron: 0 0/1 * * * ?
 * 参数示例: {"instanceId":"un7BDaG7ETq4RgjhX7Mz1"}
 */
@Component("rdsMockTask")
public class RdsMockTask implements ITask {
    private Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private MetricService metricService;

    @Qualifier("esRestClient")
    @Autowired
    private RestHighLevelClient esRestClient;

    @Override
    public void run(String params) {
        JSONObject paramsJson = JSONObject.parseObject(params);
        String instanceId = paramsJson.getString("instanceId");
        Map<String, Object> ecsInstanceData = generateRdsInstanceData(instanceId);

        // 如果索引不存在，则创建索引
        if (!isIndexExist()) {
            synchronized (RdsMockTask.class) {
                if (!isIndexExist()) {
                    createIndexMapping("rds", Constant.RDS_MAPPING);
                }
            }
        }

        IndexRequest indexRequest = new IndexRequest("rds").source(ecsInstanceData);

        try {
            esRestClient.index(indexRequest, ElasticSearchConfig.COMMON_OPTIONS);
            log.debug("{}实例插入rds数据成功", instanceId);
        } catch (IOException e) {
            log.error("{}实例插入rds数据失败", instanceId);
            e.printStackTrace();
        }
    }

    /**
     * 创建ecs在elasticsearch中的mapping
     * @param mapping mapping
     * @param index index名称
     */
    private void createIndexMapping(String index,String mapping) {
        CreateIndexRequest request = new CreateIndexRequest(index);

        request.settings(Settings.builder()
                .put("index.number_of_shards", 5)
                .put("index.number_of_replicas", 2)
        );

        request.mapping(mapping, XContentType.JSON);

        try {
            esRestClient.indices().create(request, ElasticSearchConfig.COMMON_OPTIONS);
            log.debug("创建mapping成功: {}",index);
        } catch (IOException e) {
            log.error("创建"+index+"的mapping时出现异常",e.getMessage());
        }
    }

    /**
     * 构造ECS实例数据
     * @return 待插入的实例数据
     */
    private Map<String,Object> generateRdsInstanceData(String instanceId){
        Map<String, Object> instanceData = new HashMap<>();
        instanceData.put("time",new Date());
        instanceData.put("instanceId",instanceId);
        List<MetricEntity> metricEntities = metricService.list(new QueryWrapper<MetricEntity>().eq("type", Constant.InstanceType.RDS.getValue()));

        metricEntities.forEach(metric->{
            String unit=metric.getUnit();
            if(Constant.MetricUnitType.BitRate.getValue().equalsIgnoreCase(unit)){
                Integer bitRate=(int) RandomUtils.getGaussianValue(800,120*120);
                while (bitRate<0){
                    bitRate=(int)RandomUtils.getGaussianValue(800,120*120);
                }
                instanceData.put(metric.getName(),bitRate);
            }else if(Constant.MetricUnitType.Byte.getValue().equalsIgnoreCase(unit)){
                Integer byteValue=(int)RandomUtils.getGaussianValue(25,4*4);
                while (byteValue<0){
                    byteValue=(int)RandomUtils.getGaussianValue(25,4*4);
                }
                instanceData.put(metric.getName(),byteValue);
            }else if(Constant.MetricUnitType.ByteRate.getValue().equalsIgnoreCase(unit)){
                Integer byteRate=(int)RandomUtils.getGaussianValue(100,15*15);
                while (byteRate<0){
                    byteRate=(int)RandomUtils.getGaussianValue(100,15*15);
                }
                instanceData.put(metric.getName(),byteRate);
            }else if(Constant.MetricUnitType.Count.getValue().equalsIgnoreCase(unit)){
                Integer count=(int)RandomUtils.getGaussianValue(10,3);
                while (count<0){
                    count=(int)RandomUtils.getGaussianValue(10,3);
                }

                instanceData.put(metric.getName(),count);
            }else if(Constant.MetricUnitType.CountRate.getValue().equalsIgnoreCase(unit)){
                Integer countRate=(int)RandomUtils.getGaussianValue(40,6);
                while (countRate.intValue()<0){
                    countRate=(int)RandomUtils.getGaussianValue(40,6);
                }

                instanceData.put(metric.getName(),countRate);
            }else if(Constant.MetricUnitType.MB.getValue().equalsIgnoreCase(unit)){
                Float MB=(float)RandomUtils.getGaussianValue(1000,150*150);
                while (MB.intValue()<0){
                    MB=(float)RandomUtils.getGaussianValue(1000,150*150);
                }
                instanceData.put(metric.getName(),MB);
            }else if(Constant.MetricUnitType.Percent.getValue().equalsIgnoreCase(unit)){
                Float percent=(float) RandomUtils.getGaussianValue(50,8*8);
                while (percent.intValue()<0||percent.intValue()>100){
                    percent=(float)RandomUtils.getGaussianValue(50,8*8);
                }

                instanceData.put(metric.getName(),percent);
            }else if(Constant.MetricUnitType.Second.getValue().equalsIgnoreCase(unit)){
                Double second=RandomUtils.getGaussianValue(3,2);
                while (second.intValue()<0){
                    second=RandomUtils.getGaussianValue(3,2);
                }

                instanceData.put(metric.getName(),second);
            }
        });
        return instanceData;
    }

    /**
     * 判断index是否存在
     * @return
     */
    private Boolean isIndexExist(){
        Boolean isExist=false;
        try {
            GetIndexRequest getIndexRequest = new GetIndexRequest("rds");
            isExist=esRestClient.indices().exists(getIndexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            log.error("获取index是否存在时出现异常",e.getMessage());
        }
        return isExist;
    }
}
